// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.commons.utils;

import java.util.HashMap;

import org.dengues.commons.DenguesCommonsPlugin;
import org.dengues.commons.i18n.Messages;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.internal.win32.OS;
import org.eclipse.swt.ole.win32.OleFrame;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Tree;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class ImageUtil {

    private static HashMap<String, Integer> pimageCount = new HashMap<String, Integer>();

    private static HashMap<String, Image> pimages = new HashMap<String, Image>();

    /**
     * Dispose of an image in cache. Once there are no more open handles to the image it will be disposed of.
     * 
     */
    public static void disposeImage(String propertyName) {

        try {

            Image image = pimages.get(propertyName);

            if (image == null) {
                return;
            }

            image.dispose();
            pimages.remove(propertyName);

            // decrease image handle count by one

            Integer handleCount = pimageCount.get(propertyName);

            if (handleCount == null) {
                handleCount = new Integer(0);
            } else {
                handleCount = new Integer(handleCount.intValue() - 1);
            }
            pimageCount.put(propertyName, handleCount);

        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * Create an image descriptor for the given image property in the text.properties file.
     * 
     * @param propertyName
     * @return
     */
    public static ImageDescriptor getDescriptor(String propertyName) {

        try {

            if (propertyName == null) {
                return null;
            }

            // get image path
            String path = Messages.getString(propertyName);

            if (path == null || path.trim().length() == 0 || !path.startsWith("icons/")) { //$NON-NLS-1$
                path = propertyName;
            }

            // create image
            return DenguesCommonsPlugin.getImageDescriptor(path);

        } catch (Exception e) {
            return null;
        }

    }

    /**
     * Get an image object from cache or create one if it doesn't exist yet. Everytime an object is retrieved, it should
     * be disposed of using the ImageUtil.disposeImage method.
     * 
     * @param propertyName
     */
    @SuppressWarnings("unchecked")//$NON-NLS-1$
    public static Image getImage(String propertyName) {

        Image image = pimages.get(propertyName);

        if (image == null) {
            image = getDescriptor(propertyName).createImage();

            if (image == null) {
                return null;
            }

            pimages.put(propertyName, image);
        }

        // increase image handle count by one

        Integer handleCount = pimageCount.get(propertyName);

        if (handleCount == null) {
            handleCount = new Integer(1);
        } else {
            handleCount = new Integer(handleCount.intValue() + 1);
        }
        pimageCount.put(propertyName, handleCount);

        return image;
    }

    private static ImageRegistry imageRegistry;

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getImageForSWT".
     * 
     * @param extension
     * @param shell
     * @return
     */
    public static Image getImageForSWT(String extension, Shell shell) {
        if (imageRegistry == null) {
            imageRegistry = new ImageRegistry();
        }
        Image image = imageRegistry.get(extension);
        if (image != null) {
            return image;
        }
        Program program = Program.findProgram(extension);
        System.out.println(Program.getExtensions());

        ImageData imageData = (program == null ? null : program.getImageData());
        if (imageData != null) {
            image = new Image(shell.getDisplay(), imageData);
            imageRegistry.put(extension, image);
        }
        return image;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "capture".
     * 
     * @param control
     * @return
     */
    public static Image capture(Control control) {

        // First try not conclusive...
        // So I should use org.eclipse.ve.internal.swt.targetvm.win32.ImageCapture class which work perfectly

        Shell shell = control.getShell();
        Rectangle boundsShell = shell.getBounds();

        Point controlPosition = control.getDisplay().map(control, control.getShell(), 0, 0);
        if (boundsShell.x < 0) {
            controlPosition.x += boundsShell.x;
        }
        if (boundsShell.y < 0) {
            controlPosition.y += boundsShell.y;
        }
        GC gc = new GC(control);
        Image image = new Image(control.getDisplay(), control.getSize().x, control.getSize().y);

        gc.copyArea(image, 0, 0);
        gc.dispose();
        return image;
        // return getImage(control, control.getSize().x, control.getSize().y, true);
    }

    /**
     * Scale image with provided percent value.
     */
    public static Image scale(Image image, int percent) {
        Transform transform = new Transform(image.getDevice());
        float scale = percent / 100f;
        int newWidth = (int) (scale * image.getImageData().width);
        int newHeight = (int) (scale * image.getImageData().height);
        transform.scale(scale, scale);
        GC gc = new GC(image);
        gc.setTransform(transform);
        gc.drawImage(image, 0, 0);

        Image newImage = new Image(image.getDevice(), newWidth, newHeight);
        gc.copyArea(newImage, 0, 0);
        return newImage;
    }

    /**
     * Save an image in a file.
     * 
     * @param image
     * @param file
     * @param format SWT.IMAGE_BMP, SWT.IMAGE_GIF, etc.
     */
    public static void save(Image image, String filePath, int format) {
        ImageLoader loader = new ImageLoader();
        loader.data = new ImageData[] { image.getImageData() };
        loader.save(filePath, format);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getImage".
     * 
     * @param aControl
     * @return
     */
    public static Image getImage(Control aControl) {
        synchronized (aControl) {
            Rectangle rect = aControl.getBounds();
            if (rect.width <= 0 || rect.height <= 0)
                return null;
            Image image = new Image(aControl.getDisplay(), rect.width, rect.height);
            int WM_PRINT = 0x0317;
            // int WM_PRINTCLIENT = 0x0318;
            // int PRF_CHECKVISIBLE = 0x00000001;
            int PRF_NONCLIENT = 0x00000002;
            int PRF_CLIENT = 0x00000004;
            int PRF_ERASEBKGND = 0x00000008;
            int PRF_CHILDREN = 0x00000010;
            // int PRF_OWNED = 0x00000020;
            int print_bits = PRF_NONCLIENT | PRF_CLIENT | PRF_ERASEBKGND;
            // This method does not print immediate children because the z-order
            // doesn't work correctly and needs to be
            // dealt with separately, however Table's TableColumn widgets are
            // children so must be handled differently
            boolean specialClass = aControl instanceof Table || aControl instanceof Browser || aControl instanceof OleFrame
                    || aControl instanceof CCombo;
            try {
                specialClass |= aControl instanceof Spinner;
            } catch (NoClassDefFoundError e) {
            } // might not be on 3.1 of SWT
            if (specialClass) {
                print_bits |= PRF_CHILDREN;
            }
            GC gc = new GC(image);
            // Need to handle cases where the GC font isn't automatically set by the
            // control's image (e.g. CLabel)
            // see bug 98830 (https://bugs.eclipse.org/bugs/show_bug.cgi?id=98830)
            Font f = aControl.getFont();
            if (f != null)
                gc.setFont(f);
            int hwnd = aControl.handle;
            if (aControl instanceof Tree) {
                int hwndParent = OS.GetParent(hwnd);
                if (hwndParent != aControl.getParent().handle) {
                    hwnd = hwndParent;
                    print_bits |= PRF_CHILDREN;
                }
            }
            OS.SendMessage(hwnd, WM_PRINT, gc.handle, print_bits);
            gc.dispose();
            return image;
        }
    }
}
